#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define DERR        0   /* error */
#define DWAN        1   /* warning */
#define DINF        2   /* information */
#define DNOT        3   /* note */
#define DBUG        4   /* debug */
#define DIGN        5   /* ignore */

/**
 * dmsg: debug message
 * dlog: debug log
 */
#define dmsg(lvl, fmt, arg...)  if(lvl <= dlvl) {                                                   \
                                    printf(fmt, ##arg);                                             \
                                }

#define dlog(lvl, fmt, arg...)  if(lvl <= dlvl) {                                                   \
                                    printf("[%04d][%s] "fmt"\r\n", __LINE__, __FUNCTION__, ##arg);  \
                                }

int dlvl = DBUG;

/*


   AA
  A  A
 A    A
 A    A
 A    A
 A    A
 A    A
 A    A
 A    A
  A  A
   AA


-------------------------------------


   XX
  XAAX
 XAXXAX
XAX  XAX
XAX  XAX
XAX  XAX
XAX  XAX
XAX  XAX
XAX  XAX
XAX  XAX
 XAXXAX
  XAAX
   XX

-------------------------------------


   XX
  X  X
 X XX X
X X  X X
X X  X X
X X  X X
X X  X X
X X  X X
X X  X X
X X  X X
 X XX X
  X  X
   XX

*/

#define HOLLOW_MARK1            'A'
#define HOLLOW_MARK2            'X'
#define HOLLOW_MARK3            ' '

/* gray 一维为行, 二维为列 */
/**
 * @brief 点阵字模转化为灰度字模(灰度图片)
 * @note  点阵字模, 一个bit表示一个显示像素
 * @note  灰度字模, 一个Byte表示一个显示像素, 可以简单理解为灰度图片
 */
int hollow_dot2gray(uint32_t width, uint32_t height, uint8_t *dot, uint8_t *gray)
{
    int i = 0;                  // 用于遍历点阵字模的每一个byte
    int j = 0;                  // 用于遍历byte中的每一个bit
    int byte_total = 0;         // 字模总共有多少个byte
    int byte_per_column = 0;    // 字模一列有多少个byte

    /* 扫描方式决定这里的计算方法, (阴码-逐列-逆向) */
    byte_per_column = (height + 7) / 8;
    byte_total = width * byte_per_column;
    dlog(DBUG, "byte_per_column = %d", byte_per_column);
    dlog(DBUG, "byte_total      = %d", byte_total);

    for(i = 0; i < byte_total; i++)
    {
        for(j = 0; j < 8; j++)
        {
            int x = (i % byte_per_column) * 8 + j;              // x表示点阵字模的行号, 从上至下递增
            int y = i / byte_per_column;                        // y表示点阵字模的列号, 从做至右递增
            dlog(DIGN, "(%2d, %2d)", x, y);

            /* 强行使用一维数组当做二维数组来用, 是因为二维数组作为函数参数需要指定第二维的元素个数 */
            gray[x * width + y] = dot[i] & (0x1 << j) ? HOLLOW_MARK1 : HOLLOW_MARK3;
        }
    }

    return 0;
}

/**
 * @brief 灰度字模(灰度图片)转化为点阵字模
 * @note  灰度字模, 一个Byte表示一个显示像素, 可以简单理解为灰度图片
 * @note  点阵字模, 一个bit表示一个显示像素
 */
int hollow_gray2dot(uint32_t width, uint32_t height, uint8_t *gray, uint8_t *dot)
{
    int x = 0;                  // x表示点阵字模的行号, 从上至下递增
    int y = 0;                  // y表示点阵字模的列号, 从做至右递增
    int byte_total = 0;         // 字模总共有多少个byte
    int byte_per_column = 0;    // 字模一列有多少个byte

    /* 清空点阵字模数据 */
    /* 扫描方式决定这里的计算方法, (阴码-逐列-逆向) */
    byte_per_column = (height + 7) / 8;
    byte_total = width * byte_per_column;
    memset(dot, 0, byte_total);

    for(x = 0; x < height; x++)
    {
        for(y = 0; y < width; y++)
        {
            if(HOLLOW_MARK2 == gray[x * width + y])
            {
                dot[y * byte_per_column + x / 8] |= 1 << (x % 8);
            }
        }
    }

    return 0;
}

/**
 * @brief 灰度字模添加边框
 * @note  灰度字模, 一个Byte表示一个显示像素
 */
int hollow_border_add(uint32_t width, uint32_t height, uint8_t *gray)
{
    int i;

    for(i = 0; i < width * height; i++)
    {
        if(gray[i] == HOLLOW_MARK1)
        {
            int x = i / width;
            int y = i % width;

            // 上
            if(x > 0)
            {
                if(gray[(x - 1) * width + y] != HOLLOW_MARK1)
                {
                    gray[(x - 1) * width + y] = HOLLOW_MARK2;
                }
            }

            // 下
            if(x < (height - 1))
            {
                if(gray[(x + 1) * width + y] != HOLLOW_MARK1)
                {
                    gray[(x + 1) * width + y] = HOLLOW_MARK2;
                }
            }

            // 左
            if(y > 0)
            {
                if(gray[x * width + y - 1] != HOLLOW_MARK1)
                {
                    gray[x * width + y - 1] = HOLLOW_MARK2;
                }
            }

            // 右
            if(y < (width - 1))
            {
                if(gray[x * width + y + 1] != HOLLOW_MARK1)
                {
                    gray[x * width + y + 1] = HOLLOW_MARK2;
                }
            }
        }
    }
}

/**
 * @brief 灰度字模进行镂空操作, 仅保留边框
 * @note  灰度字模, 一个Byte表示一个显示像素
 */
int hollow_out(uint32_t width, uint32_t height, uint8_t *gray)
{
    int i;

    for(i = 0; i < width * height; i++)
    {
        if(gray[i] == HOLLOW_MARK1)
        {
            gray[i] = HOLLOW_MARK3;
        }
    }
}

/**
 * @brief 灰度字模打印接口, 打印到终端方便调试查看
 * @note  灰度字模, 一个Byte表示一个显示像素
 */
int print_number(uint32_t width, uint32_t height, uint8_t *gray)
{
    int i;

    for(i = 0; i < width * height; i++)
    {
        printf("%c", gray[i]);
        if(i % width == (width - 1))
        {
            printf("\n");
        }
    }

    printf("-------------------------------------\n");

    return 0;
}

/**
 * @brief 灰度字模转化为ARGB8888字符数组
 * @note  灰度字模, 一个Byte表示一个显示像素
 */
int print_convert(uint32_t width, uint32_t height, uint8_t *gray)
{
    int i;

    for(i = 0; i < width * height; i++)
    {
        if(gray[i] == HOLLOW_MARK1)
        {
            printf("0x%08x, ", 0xFFFFFFFF);
        }
        else if(gray[i] == HOLLOW_MARK2)
        {
            printf("0x%08x, ", 0xFF010101);
        }
        else
        {
            printf("0x%08x, ", 0x00000000);
        }

        if(i % width == (width - 1))
        {
            printf("\n");
        }
    }
    printf("-------------------------------------\n");
    return 0;
}

int main(int argc, char **argv)
{
    char        iname[32];
    FILE       *ifile       = NULL;
    uint8_t    *ibuf        = NULL;
    uint32_t    isize       = 0;
    int         ircnt       = 0;

    char        oname[32];
    FILE       *ofile       = NULL;
    uint8_t    *obuf        = NULL;
    uint32_t    osize       = 0;
    int         owcnt       = 0;

    int         width       = 0;
    int         height      = 0;
    int         fontsize    = 0;            // 字体大小
    int         graylen     = 0;            // 灰度图片大小
    uint8_t    *gbuf        = NULL;         // 灰度图片内存
    int         c           = 0;

    /* 打印函数使用方法 */
    if (argc != 4)
    {
        printf("usage   : %s <input> <output> <size>\n", argv[0]);
        printf("eg      : %s font16x8.fon  hollow16x8.fon  16\n", argv[0]);
        printf("eg      : %s font32x16.fon hollow32x16.fon 32\n", argv[0]);
        printf("eg      : %s font64x32.fon hollow64x32.fon 64\n", argv[0]);
        printf("\n");
        printf("size    :\n");
        printf("     16 : 16x8\n");
        printf("     32 : 32x16\n");
        printf("     64 : 64x32\n");
        return -1;
    }

    /* 获取字体大小 */
    sscanf(argv[3], "%d", &fontsize);
    dmsg(DBUG, "fontsize    = %d\n", fontsize);
    if(fontsize != 16 && fontsize != 32 && fontsize != 64)
    {
        printf("err: size %d not support\n", fontsize);
        return -1;
    }

    /* 解析输入参数得到文件名 */
    strcpy(iname, argv[1]);
    strcpy(oname, argv[2]);
    dmsg(DBUG, "iname       = %s\n", iname);
    dmsg(DBUG, "oname       = %s\n", oname);

    /* 计算单个字模大小 */
    width = fontsize / 2;
    height = fontsize;
    graylen = width * height;
    isize = graylen / 8;
    osize = isize;
    dmsg(DBUG, "isize       = %d\n", isize);
    dmsg(DBUG, "osize       = %d\n", osize);

    /* 申请数据内存 */
    ibuf = (uint8_t *)malloc(isize);
    if(NULL == ibuf)
    {
        printf("err: malloc ibuf failed\n");
        return -1;
    }

    obuf = (uint8_t *)malloc(osize);
    if(NULL == obuf)
    {
        free(ibuf);
        printf("err: malloc obuf failed\n");
        return -1;
    }

    gbuf = (uint8_t *)malloc(graylen);
    if(NULL == gbuf)
    {
        free(ibuf);
        free(obuf);
        printf("err: malloc gbuf failed\n");
        return -1;
    }

    /* 读取输入文件, 创建输出文件 */
    ifile = fopen(iname, "r");
    if(NULL == ifile)
    {
        free(ibuf);
        free(obuf);
        free(gbuf);
        printf("err: can not open %s file\n", iname);
        return -1;
    }

    ofile = fopen(oname, "w");
    if(NULL == ofile)
    {
        free(ibuf);
        free(obuf);
        free(gbuf);
        fclose(ifile);
        printf("err: can not create %s file\n", oname);
        return -1;
    }

    for(c = 0; c < 128; c++)
    {
        memset(ibuf, 0, isize);
        memset(obuf, 0, osize);
        memset(gbuf, 0, graylen);

        ircnt = fread(ibuf, 1, isize, ifile);
        if(ircnt != isize)
        {
            free(ibuf);
            free(obuf);
            free(gbuf);
            fclose(ifile);
            fclose(ofile);
            printf("err: fread(%d), rcnt = %d", c, ircnt);
            return -1;
        }

        /* 点阵字模转化为灰度图片 */
        hollow_dot2gray(width, height, ibuf, gbuf);
        // print_number(width, height, gbuf);

        /* 描边 */
        hollow_border_add(width, height, gbuf);
        // print_number(width, height, gbuf);

        /* 镂空 */
        hollow_out(width, height, gbuf);
        print_number(width, height, gbuf);

        /* 灰度图片转化为点阵字模 */
        hollow_gray2dot(width, height, gbuf, obuf);

        owcnt = fwrite(obuf, 1, osize, ofile);
        if(owcnt != osize)
        {
            free(ibuf);
            free(obuf);
            free(gbuf);
            fclose(ifile);
            fclose(ofile);
            printf("err: fwrite(%d), wcnt = %d", c, owcnt);
            return -1;
        }
    }

    fclose(ifile);
    fclose(ofile);
    free(ibuf);
    free(obuf);
    free(gbuf);

    return 0;
}
